home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / xprz351s.lha / Utils.c < prev    next >
C/C++ Source or Header  |  1995-06-29  |  48KB  |  1,503 lines

  1.  /**********************************************************************
  2.   * Utils.c: Miscellaneous support routines for xprzmodem.library;
  3.   * Version 2.10, 12 February 1991, by Rick Huebner.
  4.   * Released to the Public Domain; do as you like with this code.
  5.   *
  6.   * Version 2.50, 15 November 1991, by William M. Perkins.  Added code
  7.   * to update_rate() function in utils.c to avoid the Guru # 80000005
  8.   * you would have gotten if you had decided to adjust the system clock
  9.   * back during an upload or download.
  10.   *
  11.   * Mysprintf() function to replace sprintf() and proto code to use
  12.   * libinit.o and linent.o library code was supplied by Jim Cooper of SAS.
  13.   *
  14.   * Version 2.61, 3 July 1993 Mysprintf changed to xprsprintf(), written
  15.   * in Assembler, because under SAS/C the old code running not correctly.
  16.   *
  17.   * Version 2.62, 27 July 1993 build in variable Blocksize.
  18.   *
  19.   * Version 2.63, 30 July 1993 build in locale, by Rainer Hess
  20.   *
  21.   * Version 2.64,  3 Aug 1993 global vaiable Blocksize, now in
  22.   *                 struct Vars, by Rainer Hess
  23.   *
  24.   *                4 Aug 1993 changes in update_rate() function because
  25.   * it always GURU 8000 0005 on little files (testet with 2 byte-file)
  26.   * when you send. If on receiver the file exists when receiver ask for
  27.   * overwrite, the machine crash if you click overwrite on receiver.
  28.   * Testet on Term 3.4 -> Ncomm 2.0, by Rainer Hess
  29.   *
  30.   * Version 3.2   11 Nov 1994 modifications to implement FTN operations
  31.   *               by Roert Williamson
  32.   * Version 3.2   19 Nov 1994 version string added, XPR 2.001 support added
  33.   * Version 3.5   Jan 1,1994 added rxtimeout, xpr2ext setup options   
  34.   * Version 3.52  June 1995 , fix incorrect values for certain setup options
  35.   **********************************************************************/
  36.  
  37. #include "xprzmodem_all.h"
  38.  
  39. #define CATCOMP_NUMBERS
  40. #include "xprzmodem_catalog.h"
  41.  
  42.  
  43. /*
  44.  * Transfer options to use if XProtocolSetup not called
  45.  */
  46. #ifdef zedzap
  47. struct SetupVars Default_Config =
  48. {
  49.   NULL,       /* = *matchptr  */
  50.   NULL,       /* = *bufpos    */
  51.   0,          /* = buflen     */
  52.   "N",        /* option_t[2]  Set Text translation mode */
  53.   "R",        /* option_o[2]  Overwrite mode */
  54.   "16",       /* option_b[8]  Buffer size */
  55.   "0",        /* option_f[8]  Frame size */
  56.   "30",       /* option_e[8]  Error count */
  57.   "N",        /* option_s[4]  Send full directory path */
  58.   "N",        /* option_r[4]  Receive full directory path */
  59.   "N",        /* option_a[4]  Auto-activate mode */
  60.   "N",        /* option_d[4]  Delete after sending */
  61.   "Y",        /* option_k[4]  Keep partial files */
  62.   "",         /* option_p[256] Path to use for received files */
  63.   "8192",     /* option_m[8]  Set maximum packet size */
  64.   "0",        /* option_c[8]  Set Link BPS Rate */
  65.   "Y",        /* option_n[4]  Send if there are no files */
  66.   "N",        /* option_q[4]  Enable DirectZap escape only CAN */
  67.   "Y",        /* option_z[4]  Enable FTN mode */
  68.   "Y",        /* option_y[4]  Enable XPR 2.001 results */
  69.   "100"       /* option_x[8]  StartTimeout */
  70. };
  71. #else
  72. struct SetupVars Default_Config =
  73. {
  74.   NULL,       /* = *matchptr  */
  75.   NULL,       /* = *bufpos    */
  76.   0,          /* = buflen     */
  77.   "C",        /* option_t[2]  Set Text translation mode */
  78.   "N",        /* option_o[2]  Overwrite mode */
  79.   "16",       /* option_b[8]  Buffer size */
  80.   "0",        /* option_f[8]  Frame size */
  81.   "10",       /* option_e[8]  Error count */
  82.   "N",        /* option_s[4]  Send full directory path */
  83.   "N",        /* option_r[4]  Receive full directory path */
  84.   "Y",        /* option_a[4]  Auto-activate mode */
  85.   "N",        /* option_d[4]  Delete after sending */
  86.   "Y",        /* option_k[4]  Keep partial files */
  87.   "",         /* option_p[256] Path to use for received files */
  88.   "1024",     /* option_m[8]  Set maximum packet size */
  89.   "0",        /* option_c[8]  Set Link BPS Rate */
  90.   "N",        /* option_n[4]  Send if there are no files */
  91.   "N",        /* option_q[4]  Enable DirectZap escape only CAN */
  92.   "N",        /* option_z[4]  Enable FTN mode */
  93.   "N",        /* option_y[4]  Enable XPR 2.001 results */
  94.   "100"       /* option_x[8]  StartTimeout */
  95. };
  96. #endif
  97.  
  98. #ifdef DEBUGLOG
  99. UBYTE DebugName[] = "T:XDebug.Log";
  100. void *DebugLog = NULL;
  101. #endif
  102.  
  103. struct DosLibrary *DOSBase;
  104. struct ExecBase *SysBase;
  105.  
  106. #ifdef UP_TO_2X
  107. struct Library *UtilityBase;
  108. #endif
  109.  
  110. #define LIBRARY_ANY 0L
  111.  
  112. #define LocaleBase li.li_LocaleBase
  113. #define catalog    li.li_Catalog
  114.  
  115. struct LocaleInfo li;
  116.  
  117. struct TagItem LocalTags[3] =
  118. {
  119.   OC_BuiltInLanguage, (ULONG) "english",
  120.   OC_Version, 1,
  121.   TAG_DONE
  122. };
  123.  
  124. /**********************************************************
  125.  *      int __UserLibInit(struct Library *libbase)
  126.  **********************************************************/
  127. int __saveds __asm
  128. __UserLibInit (register __a6 struct MyLibrary *libbase)
  129. {
  130.   SysBase = *(struct ExecBase **) 4L;
  131.   if (!(DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", LIBRARY_ANY)))
  132.     return (RETURN_FAIL);
  133.  
  134. #ifdef UP_TO_2X
  135.   if (!(UtilityBase = OpenLibrary ("utility.library", 37L)))
  136.     return (RETURN_FAIL);
  137. #endif
  138.  
  139.   if (LocaleBase = OpenLibrary ("locale.library", 38L))
  140.     catalog = OpenCatalogA (NULL, "xprzmodem.catalog", &LocalTags[0]);
  141.  
  142.   return (RETURN_OK);
  143. }                                /* End of __UserLibInit() */
  144.  
  145. /**********************************************************
  146.  *      void __UserLibCleanup(struct Library *libbase)
  147.  **********************************************************/
  148. void __saveds __asm
  149. __UserLibCleanup (register __a6 struct MyLibrary *libbase)
  150. {
  151.   if (DOSBase)
  152.     CloseLibrary ((struct Library *) DOSBase);
  153.  
  154. #ifdef UP_TO_2X
  155.   if (UtilityBase)
  156.     CloseLibrary (UtilityBase);
  157. #endif
  158.  
  159.   if (LocaleBase)
  160.     {
  161.       if (catalog)
  162.         CloseCatalog (catalog);
  163.       CloseLibrary (LocaleBase);
  164.     }
  165. }                                /* End of __UserLibCleanup() */
  166.  
  167. /**********************************************************
  168.  *      long XProtocolSetup(struct XPR_IO *xio)
  169.  *
  170.  * Called by comm program to set transfer options
  171.  **********************************************************/
  172. long __saveds __asm
  173. XProtocolSetup (register __a0 struct XPR_IO *xio)
  174. {
  175.   struct SetupVars *sv, tempsv;
  176.   struct xpr_option *option_ptrs[19];
  177.   struct xpr_option *optr, xo_hdr, 
  178.     xo_t, xo_o, xo_b, xo_f, xo_e, xo_s,
  179.     xo_r, xo_a, xo_d, xo_k, xo_p, xo_m, 
  180.     xo_c, xo_n, xo_q, xo_z, xo_y, xo_x;
  181.   UBYTE buf[512], *p;
  182.   long i, len;
  183.  
  184.   /* Allocate memory for transfer options string */
  185.   if (!(sv = (void *) xio->xpr_data))
  186.   {
  187. /*      xio->xpr_data = AllocMem ((ULONG) sizeof (struct SetupVars), MEMF_CLEAR); */
  188.       xio->xpr_data = AllocMem ((long) sizeof (struct SetupVars), MEMF_CLEAR);
  189.       if (!(sv = (void *) xio->xpr_data))
  190.         {
  191.           ioerr (xio, "Not enough memory!");
  192.           return XPRS_FAILURE;
  193.         }
  194.       /* Start out with default options; merge user changes into defaults */
  195.       *sv = Default_Config;
  196.   }
  197.  
  198.   /* If options string passed by comm prog, use it; else prompt user */
  199.   if (xio->xpr_filename)
  200.     strcpy (buf, xio->xpr_filename);
  201.   else
  202.   {
  203.     /* If xpr_options() implemented by comm program, use it */
  204.     if (xio->xpr_extension >= 1 && xio->xpr_options)
  205.     {
  206.         /*
  207.            * Let user edit temp copy of options so we can ignore invalid
  208.            * entries.  Have to init all this crud the hard way 'cause it's
  209.            * got to be on the stack in order to maintain reentrancy
  210.          */
  211.         tempsv = *sv;
  212.         xo_hdr.xpro_description = GetLocalString( &li, MSG_ZMODEM_OPTIONS );
  213.         xo_hdr.xpro_type = XPRO_HEADER;
  214.         xo_hdr.xpro_value = NULL;
  215.         xo_hdr.xpro_length = 0;
  216.         option_ptrs[0] = &xo_hdr;
  217.  
  218.         xo_t.xpro_description = GetLocalString( &li, MSG_TEXT_MODE );
  219.         xo_t.xpro_type = XPRO_STRING;
  220.         xo_t.xpro_value = tempsv.option_t;
  221.         xo_t.xpro_length = sizeof (tempsv.option_t);
  222.         option_ptrs[1] = &xo_t;
  223.  
  224.         xo_o.xpro_description = GetLocalString( &li, MSG_OVERWRITE_MODE );
  225.         xo_o.xpro_type = XPRO_STRING;
  226.         xo_o.xpro_value = tempsv.option_o;
  227.         xo_o.xpro_length = sizeof (tempsv.option_o);
  228.         option_ptrs[2] = &xo_o;
  229.  
  230.         xo_b.xpro_description = GetLocalString( &li, MSG_IO_BUFFER_SIZE );
  231.         xo_b.xpro_type = XPRO_LONG;
  232.         xo_b.xpro_value = tempsv.option_b;
  233.         xo_b.xpro_length = sizeof (tempsv.option_b);
  234.         option_ptrs[3] = &xo_b;
  235.  
  236.         xo_f.xpro_description = GetLocalString( &li, MSG_FRAME_SIZE );
  237.         xo_f.xpro_type = XPRO_LONG;
  238.         xo_f.xpro_value = tempsv.option_f;
  239.         xo_f.xpro_length = sizeof (tempsv.option_f);
  240.         option_ptrs[4] = &xo_f;
  241.  
  242.         xo_e.xpro_description = GetLocalString( &li, MSG_ERROR_LIMIT );
  243.         xo_e.xpro_type = XPRO_LONG;
  244.         xo_e.xpro_value = tempsv.option_e;
  245.         xo_e.xpro_length = sizeof (tempsv.option_e);
  246.         option_ptrs[5] = &xo_e;
  247.  
  248.         xo_a.xpro_description = GetLocalString( &li, MSG_AUTO_ACTIVATE_RECEIVER );
  249.         xo_a.xpro_type = XPRO_BOOLEAN;
  250.         xo_a.xpro_value = tempsv.option_a;
  251.         xo_a.xpro_length = sizeof (tempsv.option_a);
  252.         option_ptrs[6] = &xo_a;
  253.  
  254.         xo_d.xpro_description = GetLocalString( &li, MSG_DELETE_AFTER_SENDING );
  255.         xo_d.xpro_type = XPRO_BOOLEAN;
  256.         xo_d.xpro_value = tempsv.option_d;
  257.         xo_d.xpro_length = sizeof (tempsv.option_d);
  258.         option_ptrs[7] = &xo_d;
  259.  
  260.         xo_k.xpro_description = GetLocalString( &li, MSG_KEEP_PARTIAL_FILES );
  261.         xo_k.xpro_type = XPRO_BOOLEAN;
  262.         xo_k.xpro_value = tempsv.option_k;
  263.         xo_k.xpro_length = sizeof (tempsv.option_k);
  264.         option_ptrs[8] = &xo_k;
  265.  
  266.         xo_s.xpro_description = GetLocalString( &li, MSG_SEND_FULL_PATH );
  267.         xo_s.xpro_type = XPRO_BOOLEAN;
  268.         xo_s.xpro_value = tempsv.option_s;
  269.         xo_s.xpro_length = sizeof (tempsv.option_s);
  270.         option_ptrs[9] = &xo_s;
  271.  
  272.         xo_r.xpro_description = GetLocalString( &li, MSG_USE_RECEIVED_PATH );
  273.         xo_r.xpro_type = XPRO_BOOLEAN;
  274.         xo_r.xpro_value = tempsv.option_r;
  275.         xo_r.xpro_length = sizeof (tempsv.option_r);
  276.         option_ptrs[10] = &xo_r;
  277.  
  278.         xo_p.xpro_description = GetLocalString( &li, MSG_DEFAULT_RECEIVE_PATH );
  279.         xo_p.xpro_type = XPRO_STRING;
  280.         xo_p.xpro_value = tempsv.option_p;
  281.         xo_p.xpro_length = sizeof (tempsv.option_p);
  282.         option_ptrs[11] = &xo_p;
  283.  
  284.         xo_m.xpro_description = GetLocalString( &li, MSG_MAXIMUM_BLOCK_SIZE );
  285.         xo_m.xpro_type = XPRO_LONG;
  286.         xo_m.xpro_value = tempsv.option_m;
  287.         xo_m.xpro_length = sizeof (tempsv.option_m);
  288.         option_ptrs[12] = &xo_m;
  289.  
  290.         xo_c.xpro_description = GetLocalString( &li, MSG_LINK_RATE );
  291.         xo_c.xpro_type = XPRO_LONG;
  292.         xo_c.xpro_value = tempsv.option_c;
  293.         xo_c.xpro_length = sizeof (tempsv.option_c);
  294.         option_ptrs[13] = &xo_c;
  295.  
  296.         xo_n.xpro_description = GetLocalString( &li, MSG_SEND_NO_FILES );
  297.         xo_n.xpro_type = XPRO_BOOLEAN;
  298.         xo_n.xpro_value = tempsv.option_n;
  299.         xo_n.xpro_length = sizeof (tempsv.option_n);
  300.         option_ptrs[14] = &xo_n;
  301.  
  302.         xo_q.xpro_description = GetLocalString( &li, MSG_ESCAPE_ONLY_ZCAN );
  303.         xo_q.xpro_type = XPRO_BOOLEAN;
  304.         xo_q.xpro_value = tempsv.option_q;
  305.         xo_q.xpro_length = sizeof (tempsv.option_q);
  306.         option_ptrs[15] = &xo_q;
  307.  
  308.         xo_z.xpro_description = GetLocalString( &li, MSG_FTN_ZMODEM );
  309.         xo_z.xpro_type = XPRO_BOOLEAN;
  310.         xo_z.xpro_value = tempsv.option_z;
  311.         xo_z.xpro_length = sizeof (tempsv.option_z);
  312.         option_ptrs[16] = &xo_z;
  313.  
  314.         xo_y.xpro_description = GetLocalString( &li, MSG_XPR_EXT );
  315.         xo_y.xpro_type = XPRO_BOOLEAN;
  316.         xo_y.xpro_value = tempsv.option_y;
  317.         xo_y.xpro_length = sizeof (tempsv.option_y);
  318.         option_ptrs[17] = &xo_y;
  319.  
  320.         xo_x.xpro_description = GetLocalString( &li, MSG_STARTUP_TIMEOUT );
  321.         xo_x.xpro_type = XPRO_LONG;
  322.         xo_x.xpro_value = tempsv.option_x;
  323.         xo_x.xpro_length = sizeof (tempsv.option_x);
  324.         option_ptrs[18] = &xo_x;
  325.  
  326.  
  327.         /* Convert Y/N used elsewhere into "yes"/"no" required by spec */
  328.         for (i = 6; i <= 10; ++i)
  329.         {
  330.           optr = option_ptrs[i];
  331.           strcpy (optr->xpro_value, (*optr->xpro_value == 'Y') ? "yes" : "no");
  332.         }
  333.         for (i = 14; i <= 17; ++i)
  334.         {
  335.           optr = option_ptrs[i];
  336.           strcpy (optr->xpro_value, (*optr->xpro_value == 'Y') ? "yes" : "no");
  337.         }
  338.  
  339.         (*xio->xpr_options) (19L, option_ptrs);
  340.  
  341.         /* Convert "yes"/"no" or "on"/"off" into Y/N */
  342.         for (i = 6; i <= 10; ++i)
  343.         {
  344.           optr = option_ptrs[i];
  345.           strcpy (optr->xpro_value, (!stricmp (optr->xpro_value, "yes")
  346.                      || !stricmp (optr->xpro_value, "on")) ? "Y" : "N");
  347.         }
  348.         for (i = 14; i <= 17; ++i)
  349.         {
  350.           optr = option_ptrs[i];
  351.           strcpy (optr->xpro_value, (!stricmp (optr->xpro_value, "yes")
  352.                      || !stricmp (optr->xpro_value, "on")) ? "Y" : "N");
  353.         }
  354.         /* Convert xpr_options() results into parseable options string */
  355.         xprsprintf (buf, "T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,P%s,M%s,C%s,N%s,Q%s,Z%s",
  356.           tempsv.option_t, tempsv.option_o, tempsv.option_b, tempsv.option_f,
  357.           tempsv.option_e, tempsv.option_a, tempsv.option_d, tempsv.option_k,
  358.           tempsv.option_s, tempsv.option_r, tempsv.option_p, tempsv.option_m,
  359.           tempsv.option_c, tempsv.option_n, tempsv.option_q, tempsv.option_z,
  360.           tempsv.option_y, tempsv.option_x);
  361.         /* If xpr_options() not provided, try xpr_gets() instead */
  362.     }
  363.     else
  364.     {
  365.       /* Start buffer with current settings so user can see/edit them. */
  366.       xprsprintf (buf, "T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,P%s,M%s,C%s,N%s,Q%s,Z%s",
  367.           sv->option_t, sv->option_o, sv->option_b, sv->option_f,
  368.           sv->option_e, sv->option_a, sv->option_d, sv->option_k,
  369.           sv->option_s, sv->option_r, sv->option_p, sv->option_m,
  370.           sv->option_c, sv->option_n, sv->option_q, sv->option_z,
  371.           sv->option_y, sv->option_x);
  372.       if (xio->xpr_gets)
  373.         (*xio->xpr_gets) ( GetLocalString( &li, MSG_ZMODEM_OPTIONS ), buf);
  374.     }
  375.   }
  376.   /* Upshift options string for easier parsing */
  377.   strupr (buf);
  378.  
  379.   /*
  380.      * Merge new T(ext) option into current settings if given
  381.      *  "TY" = Force Text mode on,
  382.      *  "TN" = Force Text mode off,
  383.      *  "T?" = Use other end's text mode suggestion (default to binary)
  384.      *  "TC" = Ask Comm program for file type
  385.    */
  386.   if (p = find_option (buf, 'T'))
  387.   {
  388.     if (*p == 'Y' || *p == 'N' || *p == '?' || *p == 'C') *sv->option_t = *p;
  389.       else ioerr (xio,  GetLocalString( &li, MSG_INVALID_T_FLAG ));
  390.   }
  391.  
  392.   /*
  393.      * Merge new O(verwrite) option into current settings if given
  394.      *  "OY" = Yes, delete old file and replace with new one,
  395.      *  "ON" = No, prevent overwrite by appending ".dup" to avoid name collision,
  396.      *  "OR" = Resume transfer at end of existing file,
  397.      *  "OS" = Skip file if it already exists; go on to next
  398.    */
  399.   if (p = find_option (buf, 'O'))
  400.   {
  401.     if (*p == 'R' && !xio->xpr_finfo)
  402.       ioerr (xio, GetLocalString( &li, MSG_NO_XPR_FINFO ));
  403.     else if (*p == 'Y' || *p == 'N' || *p == 'R' || *p == 'S')
  404.       *sv->option_o = *p;
  405.     else ioerr (xio, GetLocalString( &li, MSG_INVALID_O_FLAG ));
  406.   }
  407.  
  408.   /*
  409.      * Merge new B(uffer) setting into current settings if given
  410.      * Size of file I/O buffer in kilobytes
  411.    */
  412.   if (p = find_option (buf, 'B'))
  413.   {
  414.     len = atol (p);
  415.     if (len < 1) len = 1;
  416.     xprsprintf (sv->option_b, "%ld", len);
  417.   }
  418.  
  419.   /*
  420.      * Merge new F(ramelength) setting into other settings if given
  421.      * Number of bytes we're willing to send or receive between ACKs.
  422.      * 0 = unlimited; nonstop streaming data
  423.    */
  424.   if (p = find_option (buf, 'F'))
  425.   {
  426.     len = atol (p);
  427.     if (len < 0) len = 0;
  428.     if (len > 0 && len < MINBLOCK) len = MINBLOCK;
  429.     xprsprintf (sv->option_f, "%ld", len);
  430.   }
  431.  
  432.   /*
  433.      * Merge new E(rror limit) setting into other settings if given
  434.      * Number of sequential errors which will cause an abort
  435.    */
  436.   if (p = find_option (buf, 'E'))
  437.   {
  438.     len = atol (p);
  439.     if (len < 1) len = 1;
  440.     if (len > 32767) len = 32767;
  441.     xprsprintf (sv->option_e, "%ld", len);
  442.   }
  443.  
  444.   /*
  445.      * Merge new A(uto-activate) setting into other settings if given
  446.      *  "AY" = Automatically call XProtocolReceive() if ZRQINIT string received
  447.      *  "AN" = Don't look for ZRQINIT; user will explicitly activate receive
  448.    */
  449.   if (p = find_option (buf, 'A'))
  450.   {
  451.     if (*p == 'Y' || *p == 'N') *sv->option_a = *p;
  452.       else ioerr (xio, GetLocalString( &li, MSG_INVALID_A_FLAG ));
  453.   }
  454.  
  455.   /*
  456.      * Merge new D(elete after sending) setting into other options
  457.      *  "DY" = Delete files after successfully sending them
  458.      *  "DN" = Don't delete files after sending
  459.    */
  460.   if (p = find_option (buf, 'D'))
  461.   {
  462.     if (*p == 'Y' && (xio->xpr_extension < 2 || !xio->xpr_unlink))
  463.       ioerr (xio, GetLocalString( &li, MSG_NO_DY_XPR_UNLINK ));
  464.     else if (*p == 'Y' || *p == 'N') *sv->option_d = *p;
  465.     else ioerr (xio, GetLocalString( &li, MSG_INVALID_D_FLAG ));
  466.   }
  467.  
  468.   /*
  469.      * Merge new K(eep partial files) setting into other options
  470.      *  "KY" = Keep partially-received file fragments to allow later resumption
  471.      *  "KN" = Delete partially-received file fragments
  472.    */
  473.   if (p = find_option (buf, 'K'))
  474.   {
  475.     if (*p == 'N' && (xio->xpr_extension < 2 || !xio->xpr_unlink))
  476.       ioerr (xio, GetLocalString( &li, MSG_NO_KN_XPR_UNLINK ));
  477.     else if (*p == 'Y' || *p == 'N') *sv->option_k = *p;
  478.     else ioerr (xio, GetLocalString( &li, MSG_INVALID_K_FLAG ));
  479.   }
  480.  
  481.   /*
  482.      * Merge new S(end full path) setting into other options
  483.      *  "SY" = Send full filename including directory path to receiver
  484.      *  "SN" = Send only simple filename portion, not including directory path
  485.    */
  486.   if (p = find_option (buf, 'S'))
  487.   {
  488.     if (*p == 'Y' || *p == 'N') *sv->option_s = *p;
  489.       else ioerr (xio, GetLocalString( &li, MSG_INVALID_S_FLAG ));
  490.   }
  491.  
  492.   /*
  493.      * Merge new R(eceive path) setting into other options
  494.      *  "RY" = Use full filename exactly as received; don't use P option path
  495.      *  "RN" = Ignore received directory path if any; use path from P option
  496.    */
  497.   if (p = find_option (buf, 'R'))
  498.   {
  499.     if (*p == 'Y' || *p == 'N') *sv->option_r = *p;
  500.       else ioerr (xio, GetLocalString( &li, MSG_INVALID_R_FLAG ));
  501.   }
  502.  
  503.   /*
  504.      * Merge new P(ath) setting into other options
  505.      *  "Pdir" = Receive files into directory "dir" if RN selected
  506.      *  "dir" can by any valid existing directory, with or without trailing "/"
  507.    */
  508.   if (p = find_option (buf, 'P'))
  509.   {
  510.     strcpy (sv->option_p, p);
  511.     p = sv->option_p + strcspn (sv->option_p, " ,\t\r\n");
  512.     *p = '\0';
  513.   }
  514.  
  515.   /* Maximum packet size. Must be <=8192 */
  516.  
  517.   if (p = find_option (buf, 'M'))
  518.   {
  519.     len = atol (p);
  520.     if (len < MINBLOCK) len = MINBLOCK;
  521.     if (len > MAXGOODNEEDED || len > KSIZE) len = KSIZE;
  522.     xprsprintf (sv->option_m, "%ld", len);
  523.   }
  524.  
  525.   /* Modify BPS Rate If We Have The BPS Rate Locked */
  526.   if (p = find_option(buf,'C'))
  527.   {
  528.     len = atol(p);
  529.     if ((len < 300)||(len > 58600)) len = 0;
  530.     xprsprintf(sv->option_c,"%ld",len);
  531.   }
  532.  
  533.   if (p = find_option(buf,'N'))
  534.   {
  535.     if (*p == 'Y' || *p == 'N') *sv->option_n = *p;
  536.       else ioerr(xio,GetLocalString( &li, MSG_INVALID_N_FLAG ));
  537.   }
  538.   if (p = find_option(buf,'Q'))
  539.   {
  540.     if (*p == 'Y' || *p == 'N') *sv->option_q = *p;
  541.       else ioerr(xio,GetLocalString( &li, MSG_INVALID_Q_FLAG ));
  542.   }
  543.   if (p = find_option(buf,'Z'))
  544.   {
  545.     if (*p == 'Y' || *p == 'N') *sv->option_z = *p;
  546.       else ioerr(xio, GetLocalString( &li, MSG_INVALID_Z_FLAG ));
  547.   }
  548.   if (p = find_option (buf, 'Y'))
  549.   {
  550.     if (*p == 'Y' || *p == 'N') *sv->option_y = *p;
  551.       else ioerr (xio, GetLocalString( &li, MSG_INVALID_Y_FLAG ));
  552.   }
  553.   if (p = find_option (buf, 'X'))
  554.   {
  555.     len = atol (p);
  556.     if (len < MINRXTO) len = MINRXTO;
  557.     if (len > MAXRXTO) len = MAXRXTO;
  558.     xprsprintf (sv->option_x, "%ld", len);
  559.   }
  560.  
  561.  
  562. #ifdef KDEBUG
  563. KPrintF("XProtocolSetup\nT%s,O%s,B%s,F%s,E%s,A%s\nD%s,K%s,S%s,R%s,P%s,M%s\nC%s,N%s,Q%s,Z%s\n",
  564.                   sv->option_t, sv->option_o, sv->option_b, sv->option_f,
  565.                   sv->option_e, sv->option_a, sv->option_d, sv->option_k,
  566.                   sv->option_s, sv->option_r, sv->option_p, sv->option_m,
  567.                   sv->option_c, sv->option_n, sv->option_q, sv->option_z,
  568.                   sv->option_y, sv->option_x);
  569.  
  570. #endif
  571.   if (*sv->option_y == 'N')
  572.   {
  573.     return (*sv->option_a == 'Y') ? 
  574.       XPRS_SUCCESS | XPRS_NORECREQ | XPRS_HOSTMON :
  575.       XPRS_SUCCESS | XPRS_NORECREQ;
  576.   }
  577.   else
  578.   {
  579.     return (*sv->option_a == 'Y') ? 
  580.       XPRS_SUCCESS | XPRS_NORECREQ | XPRS_HOSTMON | XPRS_XPR2001 | XPRS_DOUBLE :
  581.       XPRS_SUCCESS | XPRS_NORECREQ | XPRS_XPR2001 | XPRS_DOUBLE;
  582.   }
  583. }                                /* End of long XProtocolSetup() */
  584.  
  585. /**********************************************************
  586.  *      long XProtocolCleanup(struct XPR_IO *xio)
  587.  *
  588.  * Called by comm program to give us a chance to clean
  589.  * up before program ends
  590.  **********************************************************/
  591. long __saveds __asm
  592. XProtocolCleanup (register __a0 struct XPR_IO *xio)
  593. {
  594.   /* Release option memory, if any */
  595.   if (xio->xpr_data)
  596.   {
  597.     FreeMem (xio->xpr_data, (long) sizeof (struct SetupVars));
  598.     xio->xpr_data = NULL;
  599.   }
  600.  
  601.   return XPRS_SUCCESS;
  602. }                                /* End of long XProtocolCleanup() */
  603.  
  604. /**********************************************************
  605.  *      long XProtocolHostMon(struct XPR_IO *xio,
  606.  *         char *serbuff, long actual, long maxsize)
  607.  *
  608.  * Called by comm program upon our request (XPRS_HOSTMON)
  609.  * to let us monitor the incoming data stream for our
  610.  * receiver auto-activation string (ZRQINIT packet).
  611.  * We only ask for this to be called if option AY is set.
  612.  **********************************************************/
  613. long __saveds __asm
  614. XProtocolHostMon (
  615.                    register __a0 struct XPR_IO *xio,
  616.                    register __a1 char *serbuff,
  617.                    register __d0 long actual,
  618.                    register __d1 long maxsize)
  619. {
  620.   static UBYTE startrcv[] =
  621.   {
  622.     ZPAD, ZDLE, ZHEX, '0', '0'
  623.   };
  624.   struct SetupVars *sv;
  625.  
  626.   if (!(sv = (void *) xio->xpr_data))
  627.     return actual;                /* XProtocolSetup() never called?! */
  628.  
  629.   if (!sv->matchptr)
  630.     sv->matchptr = startrcv;
  631.  
  632.   /*
  633.      * Scan through serbuff to see if we can match all bytes in the start
  634.      * string in sequence.
  635.   */
  636.   for (sv->bufpos = serbuff; sv->bufpos < serbuff + actual; ++sv->bufpos)
  637.   {
  638.     if (*sv->bufpos == *sv->matchptr)
  639.     {                        /* if data matches current position in match */
  640.       ++sv->matchptr;        /* string, increment match position */
  641.       if (!*sv->matchptr)
  642.       {                        /* if at end of match string, it all matched */
  643.         sv->buflen = actual - (sv->bufpos - serbuff);
  644.         XProtocolReceive (xio);
  645.         sv->matchptr = startrcv;
  646.         actual = 0;
  647.         break;
  648.       }
  649.     }
  650.     else if (sv->matchptr > startrcv)
  651.     {                        /* mismatch?  Reset to start of match string */
  652.       sv->matchptr = startrcv;
  653.       if (*sv->bufpos == *sv->matchptr)
  654.         ++sv->matchptr;
  655.     }
  656.   }
  657.   sv->bufpos = NULL;
  658.   return actual;
  659. }
  660.  
  661. /**********************************************************
  662.  *      long XProtocolUserMon(struct XPR_IO *xio,
  663.  *         char *serbuff, long actual, long maxsize)
  664.  *
  665.  * Called by comm program to let us monitor user's inputs;
  666.  * we never ask for this to be called, but it's better to
  667.  * recover gracefully than guru the machine.
  668.  **********************************************************/
  669. long __saveds __asm
  670. XProtocolUserMon (
  671.                    register __a0 struct XPR_IO *xio,
  672.                    register __a1 char *serbuff,
  673.                    register __d0 long actual,
  674.                    register __d1 long maxsize)
  675. {
  676.   return actual;
  677. }
  678.  
  679. /**********************************************************
  680.  *      struct Vars *setup(struct XPR_IO *io)
  681.  *
  682.  * Perform setup and initializations common to both Send
  683.  * and Receive routines
  684.  **********************************************************/
  685. struct Vars *
  686. setup (struct XPR_IO *io)
  687. {
  688. /*
  689.   static long bauds[] =
  690.   {
  691.     110, 300, 1200, 2400,
  692.     4800, 9600, 19200, 31250,
  693.     38400, 57600, 76800, 115200
  694.   };
  695. */
  696.   static long bauds[] = 
  697.   { 
  698.     300,600,1200,2400,
  699.     4800,7200,9600,12000,
  700.     14400,16800,19200,31250,
  701.     38400,57600,76800,115200
  702.   };
  703.  
  704.   struct SetupVars *sv;
  705.   struct Vars *v;
  706.   long origbuf, newstatus;
  707.  
  708. #ifdef DEBUGLOG
  709.   long i, *lng;
  710. #endif
  711.  
  712.   /* Make sure comm program supports the required call-back functions */
  713.   if (!io->xpr_update)
  714.     return NULL;
  715.  
  716.   if (!io->xpr_fopen || !io->xpr_fclose || !io->xpr_fread
  717.       || !io->xpr_fwrite || !io->xpr_fseek || !io->xpr_sread
  718.       || !io->xpr_swrite)
  719.   {
  720.     ioerr (io, GetLocalString( &li, MSG_COMM_PROG_MISSING ));
  721.     return NULL;
  722.   }
  723.  
  724.   /* Hook in default transfer options if XProtocolSetup wasn't called */
  725.   if (!(sv = (void *) io->xpr_data))
  726.   {
  727. /*    io->xpr_data = AllocMem ((ULONG) sizeof (struct SetupVars), MEMF_CLEAR);  */
  728.     io->xpr_data = AllocMem ((long) sizeof (struct SetupVars), MEMF_CLEAR);
  729.     if (!(sv = (void *) io->xpr_data))
  730.     {
  731.       ioerr (io, GetLocalString( &li, MSG_NOT_ENOUGH_MEMORY ));
  732.       return NULL;
  733.     }
  734.     *sv = Default_Config;
  735.   }
  736.  
  737.   /* Allocate memory for our unshared variables, to provide reentrancy */
  738. /*  if (!(v = AllocMem ((ULONG) sizeof (struct Vars), MEMF_CLEAR))) */
  739.   if (!(v = AllocMem ((long) sizeof (struct Vars), MEMF_CLEAR)))
  740.   {
  741.   nomem:
  742.     ioerr (io, GetLocalString( &li, MSG_NOT_ENOUGH_MEMORY ));
  743.     return NULL;
  744.   }
  745.   v->Modemchar = v->Modembuf;
  746.  
  747.   /*
  748.      * Allocate memory for our file I/O buffer; if we can't get as much as
  749.      * requested, keep asking for less until we hit minimum before giving up
  750.    */
  751.   v->Filebufmax = origbuf = atol (sv->option_b) * 1024;
  752. /*  while (!(v->Filebuf = AllocMem ((ULONG) v->Filebufmax, MEMF_ANY)))  */
  753.   while (!(v->Filebuf = AllocMem (v->Filebufmax,0L)))
  754.   {
  755.     if (v->Filebufmax > 1024)  v->Filebufmax -= 1024;
  756.     else
  757.     {
  758.       FreeMem (v, (long) sizeof (struct Vars));
  759.       goto nomem;
  760.     }
  761.   }
  762.  
  763.  v->Ksize = atol(sv->option_m);
  764.  v->StartTimeout=atol(sv->option_x);
  765.  
  766.  if((v->Ksize * 2) > v->Filebufmax)
  767.   {
  768.     if(v->Filebufmax >=  1024) { v->Ksize = 512;  strcpy(sv->option_m,"512" ); }
  769.     if(v->Filebufmax >=  2048) { v->Ksize = 1024; strcpy(sv->option_m,"1024"); }
  770.     if(v->Filebufmax >=  4096) { v->Ksize = 2048; strcpy(sv->option_m,"2048"); }
  771.     if(v->Filebufmax >=  8192) { v->Ksize = 4096; strcpy(sv->option_m,"4096"); }
  772.     if(v->Filebufmax >= 16384) { v->Ksize = 8192; strcpy(sv->option_m,"8192"); }
  773. /*    v->Ksize = atol(sv->option_m);  */
  774.   }
  775.  
  776.   /* If framelength was intended to match buffer size, stay in sync */
  777.   v->Tframlen = atol (sv->option_f);
  778.   if (v->Tframlen && v->Tframlen == origbuf)
  779.     v->Tframlen = v->Filebufmax;
  780.  
  781.   v->ErrorLimit = atol (sv->option_e);
  782.  
  783.   /* Copy caller's io struct into our Vars for easier passing */
  784.   v->io = *io;
  785.  
  786. #ifdef DEBUGLOG
  787.   if (!DebugLog)
  788.     DebugLog = (char *) (*v->io.xpr_fopen) (DebugName, "w");
  789.   dlog (v, "XPR_IO struct:\n");
  790.   for (i = 0, lng = (long *) io; i < sizeof (struct XPR_IO) / 4; ++i)
  791.   {
  792.     xprsprintf (v->Msgbuf, "  %08lx\n", *lng++);
  793.     dlog (v, v->Msgbuf);
  794.   }
  795.   D (DEBUGINFO);
  796. #endif
  797.  
  798.   /* Get baud rate; set serial port mode if necessary (and possible) */
  799.   if (v->io.xpr_setserial)
  800.   {
  801.     v->Oldstatus = (*v->io.xpr_setserial) (-1L);
  802.     if (v->Oldstatus != -1)
  803.     {
  804.       /*
  805.          * ZModem requires 8 data bits, no parity (full transparency),
  806.          *  leave other settings alone
  807.        */
  808.       newstatus = v->Oldstatus & 0xFFFFE0BC;
  809.       /*
  810.          * newstatus |= on_flags; Here's where we'd turn bits on if we
  811.          * needed to
  812.        */
  813.       if (newstatus != v->Oldstatus)
  814.         (*v->io.xpr_setserial) (newstatus);
  815.       v->Baud = bauds[(newstatus >> 16) & 0xFF];
  816.  
  817. #ifdef DEBUGLOG
  818.       xprsprintf (v->Msgbuf,
  819.                   "Old serial status = %lx, new = %lx, baud = %ld\n",
  820.                   v->Oldstatus, newstatus, v->Baud);
  821.       dlog (v, v->Msgbuf);
  822.       D (DEBUGINFO);
  823. #endif
  824.     }
  825.     else
  826.       v->Baud = 2400;
  827.       /* If no xpr_setserial(), muddle along with most likely guess */
  828.   }
  829.   else
  830.     v->Baud = 2400;
  831.  
  832.   v->FTNmode = (*sv->option_z == 'Y') ? TRUE : FALSE;
  833.   v->dzap = (*sv->option_q == 'Y') ? TRUE : FALSE;
  834.   v->NoFiles = (*sv->option_n == 'Y') ? TRUE : FALSE;
  835.   v->SmallBlocks = (*sv->option_m == 1024) ? TRUE : FALSE;
  836.   v->NewBaud = atol(sv->option_c);
  837.   v->NoMask = (*sv->option_y == 'N') ? TRUE : FALSE; 
  838.   return v;
  839. }                                /* End of struct Vars *setup() */
  840.  
  841. /**********************************************************
  842.  *      void set_textmode(struct Vars *v)
  843.  *
  844.  * Set text/binary mode flags in accordance with T option
  845.  * setting
  846.  **********************************************************/
  847. void
  848. set_textmode (struct Vars *v)
  849. {
  850.   struct SetupVars *sv;
  851.   long i;
  852.  
  853. #ifdef DEBUGLOG
  854.   D (DEBUGINFO);
  855. #endif
  856.  
  857.   sv = (void *) v->io.xpr_data;
  858.   switch (*sv->option_t)
  859.     {
  860.     case 'Y':  /* Force text mode on receive; suggest text mode on send */
  861.     TY:
  862.       v->Rxascii = TRUE;
  863.       v->Rxbinary = FALSE;
  864.       v->Lzconv = ZCNL;
  865.       break;
  866.     case 'N': /* Force binary mode on receive; suggest binary mode on send */
  867.     TN:
  868.       v->Rxascii = FALSE;
  869.       v->Rxbinary = TRUE;
  870.       v->Lzconv = ZCBIN;
  871.       break;
  872.     case 'C':                        /* Ask comm program for proper mode for this file */
  873.       if (v->io.xpr_finfo)
  874.         {
  875.           i = (*v->io.xpr_finfo) (v->Filename, 2L);
  876.           if (i == 1)                /* Comm program says use binary mode */
  877.             goto TN;
  878.           if (i == 2)                /* Comm program says use text mode */
  879.             goto TY;
  880.         }
  881.       /* xpr_finfo() not provided (or failed); default to T? */
  882.     case '?':
  883.       v->Rxascii = v->Rxbinary = FALSE;
  884.       v->Lzconv = 0;
  885.       break;
  886.     }
  887. }                                /* End of void set_textmode() */
  888.  
  889. /**********************************************************
  890.  *      UBYTE *find_option(UBYTE *buf, UBYTE option)
  891.  *
  892.  * Search for specified option setting in string
  893.  **********************************************************/
  894. UBYTE *
  895. find_option (UBYTE * buf, UBYTE option)
  896. {
  897.   while (*buf)
  898.     {
  899.       buf += strspn (buf, " ,\t\r\n");
  900.       if (*buf == option)
  901.         return ++buf;
  902.       buf += strcspn (buf, " ,\t\r\n");
  903.     }
  904.  
  905.   return NULL;
  906. }                                /* End of UBYTE *find_option() */
  907.  
  908. /**********************************************************
  909.  *      void canit(struct Vars *v)
  910.  *
  911.  * send cancel string to get the other end to shut up
  912.  **********************************************************/
  913. void
  914. canit (struct Vars *v)
  915. {
  916.   static char canistr[] =
  917.   {
  918.     24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
  919.     8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0
  920.   };
  921.  
  922. #ifdef DEBUGLOG
  923.   D (DEBUGINFO);
  924. #endif
  925.  
  926.   zmputs (v, canistr);
  927. }                                /* End of void canit() */
  928.  
  929. /**********************************************************
  930.  *      void zmputs(struct Vars *v, UBYTE *s)
  931.  *
  932.  * Send a string to the modem, with processing for \336 (sleep 1 sec)
  933.  * and \335 (break signal, ignored since XPR spec doesn't support it)
  934.  **********************************************************/
  935. void
  936. zmputs (struct Vars *v, UBYTE * s)
  937. {
  938.   UBYTE c;
  939.  
  940. #ifdef DEBUGLOG
  941.   D (DEBUGINFO);
  942. #endif
  943.  
  944.   while (*s)
  945.     {
  946.       switch (c = *s++)
  947.         {
  948.         case '\336':
  949. #ifdef zedzap
  950.           XprTimeOut(50L);
  951. #else
  952.           Delay (50L);  
  953. #endif
  954.         case '\335':
  955.           break;
  956.         default:
  957.           sendline (v, c);
  958.         }
  959.     }
  960.   sendbuf (v);
  961. }                                /* End of void zmputs() */
  962.  
  963. /**********************************************************
  964.  *      void xsendline(struct Vars *v, UBYTE c)
  965.  *
  966.  * Write one character to the modem
  967.  **********************************************************/
  968. void
  969. xsendline (struct Vars *v, UBYTE c)
  970. {
  971.   v->Outbuf[v->Outbuflen++] = c;
  972.   if (v->Outbuflen >= sizeof (v->Outbuf))
  973.     sendbuf (v);
  974.  
  975. #ifdef DEBUGLOG
  976.   D (DEBUGINFO);
  977. #endif
  978.  
  979. }                                /* End of void xsendline() */
  980.  
  981. /**********************************************************
  982.  *      void sendbuf(struct Vars *v)
  983.  *
  984.  * Send any data waiting in modem output buffer
  985.  **********************************************************/
  986. void
  987. sendbuf (struct Vars *v)
  988. {
  989. #ifdef DEBUGLOG
  990.   D (DEBUGINFO);
  991. #endif
  992.  
  993.   if (v->Outbuflen)
  994.     {
  995.       (*v->io.xpr_swrite) (v->Outbuf, (long) v->Outbuflen);
  996.       v->Outbuflen = 0;
  997.     }
  998. }                                /* End of void sendbuf() */
  999.  
  1000. /**********************************************************
  1001.  *      short readock(struct Vars *v, short tenths)
  1002.  *
  1003.  * Get a byte from the modem;
  1004.  * return TIMEOUT if no read within timeout tenths of a
  1005.  * second, return RCDO if carrier lost or other fatal error
  1006.  * (sread returns -1).  Added in some buffering so we
  1007.  * wouldn't hammer the system with single-byte serial port
  1008.  * reads.  Also, the buffering makes char_avail() a lot
  1009.  * easier to implement.
  1010.  **********************************************************/
  1011. short
  1012. readock (struct Vars *v, short tenths)
  1013. {
  1014.   long t;
  1015.  
  1016. #ifdef DEBUGLOG
  1017.   D (DEBUGINFO);
  1018. #endif
  1019.  
  1020.   /* If there's data waiting in our buffer, return next byte */
  1021.   if (v->Modemcount)
  1022.     {
  1023.     gotdata:
  1024.       --v->Modemcount;
  1025.       return (short) (*v->Modemchar++);
  1026.     }
  1027.   /*
  1028.      * Our buffer is empty; see if there's anything waiting in system buffer.
  1029.      * If the caller is in a hurry, don't wait around, but if it can spare
  1030.      * a half second, wait a bit and build up some input so we don't do as
  1031.      * many sread() calls.
  1032.    */
  1033.   t = (tenths < 5) ? 0 : 500000;
  1034.  
  1035. #ifdef DEBUGLOG
  1036.   xprsprintf (v->Msgbuf,
  1037.               "Input buffer empty; calling sread for %ld bytes, %ld usec\n",
  1038.               (long) sizeof (v->Modembuf), t);
  1039.   dlog (v, v->Msgbuf);
  1040.   D (DEBUGINFO);
  1041. #endif
  1042.   v->Modemcount = (*v->io.xpr_sread) (v->Modembuf, (long) sizeof (v->Modembuf), t);
  1043.  
  1044. #ifdef DEBUGLOG
  1045.   xprsprintf (v->Msgbuf, "   sread returned %ld\n", v->Modemcount);
  1046.   dlog (v, v->Msgbuf);
  1047.   D (DEBUGINFO);
  1048. #endif
  1049.   if (v->Modemcount < 0)        /* Carrier dropped or other fatal error; abort */
  1050.     {
  1051.       v->Modemcount = 0;
  1052.       return RCDO;
  1053.     }
  1054.   else if (!v->Modemcount)        /* Nothing in system buffer; try waiting */
  1055.     {
  1056.       t = tenths * 100000L - t;
  1057. #ifdef DEBUGLOG
  1058.       xprsprintf (v->Msgbuf, "   calling sread for 1 byte, %ld usec\n", t);
  1059.       dlog (v, v->Msgbuf);
  1060.       D (DEBUGINFO);
  1061. #endif
  1062.       v->Modemcount = (*v->io.xpr_sread) (v->Modembuf, 1L, t);
  1063. #ifdef DEBUGLOG
  1064.       xprsprintf (v->Msgbuf, "   sread returned %ld\n", v->Modemcount);
  1065.       dlog (v, v->Msgbuf);
  1066.       D (DEBUGINFO);
  1067. #endif
  1068.       if (v->Modemcount < 0)
  1069.         {
  1070.           v->Modemcount = 0;
  1071.           return RCDO;
  1072.         }
  1073.       else if (!v->Modemcount)        /* Nothing received in time */
  1074.         return TIMEOUT;
  1075.     }
  1076.   v->Modemchar = v->Modembuf;        /* Reset buffer pointer to start of data */
  1077.   goto gotdata;
  1078. }                                /* End of short readock() */
  1079.  
  1080. /**********************************************************
  1081.  *      char char_avail(struct Vars *v)
  1082.  *
  1083.  * Check if there's anything available to read from the
  1084.  * modem
  1085.  **********************************************************/
  1086. char
  1087. char_avail (struct Vars *v)
  1088. {
  1089. #ifdef DEBUGLOG
  1090.   D (DEBUGINFO);
  1091. #endif
  1092.  
  1093.   if (v->Modemcount)
  1094.     return TRUE;
  1095.  
  1096.   /* No data in our buffer; check system's input buffer */
  1097.   v->Modemcount = (*v->io.xpr_sread)
  1098.     (v->Modembuf, (long) sizeof (v->Modembuf), 0L);
  1099.   if (v->Modemcount < 1)        /* Nothing in system buffer either */
  1100.     {
  1101.       v->Modemcount = 0;
  1102.       return FALSE;
  1103.     }
  1104.   else
  1105.     /* System buffer had something waiting for us */
  1106.     {
  1107.       v->Modemchar = v->Modembuf;
  1108.       return TRUE;
  1109.     }
  1110. }                                /* End of char char_avail() */
  1111.  
  1112. /**********************************************************
  1113.  *      void update_rate(struct Vars *v)
  1114.  *
  1115.  * Update the elapsed time, expected total time, and
  1116.  * effective data transfer rate values for status display
  1117.  **********************************************************/
  1118. void
  1119. update_rate (struct Vars *v)
  1120. {
  1121.   ULONG sent, elapsed, expect;
  1122.   short hr, min;
  1123.   struct timeval tv;
  1124.  
  1125. #ifdef DEBUGLOG
  1126.   D (DEBUGINFO);
  1127. #endif
  1128.  
  1129.   /* Compute effective data rate so far in characters per second */
  1130.   sent = v->xpru.xpru_bytes - v->Strtpos;
  1131.   getsystime (&tv);
  1132.   elapsed = (tv.tv_secs & 0x7FFFFF) * 128 + tv.tv_micro / 8192;
  1133.   elapsed -= (v->Starttime.tv_secs & 0x7FFFFF) * 128 + v->Starttime.tv_micro / 8192;
  1134.   if (elapsed < 128 || elapsed > 0x7FFFFF)
  1135.     elapsed = 128;
  1136.   /*
  1137.      * If we haven't transferred anything yet (just starting), make reasonable
  1138.      * guess (95% throughput); otherwise, compute actual effective transfer
  1139.      * rate
  1140.    */
  1141.  
  1142.   if (v->NewBaud == 0)
  1143.     v->xpru.xpru_datarate = (sent) ? (sent * 128 / elapsed) : (v->Baud * 95 / 1000);
  1144.   else
  1145.     v->xpru.xpru_datarate = (sent) ? (sent * 128 / elapsed) : (v->NewBaud * 95 / 1000);
  1146.  
  1147.   /* Compute expected total transfer time based on data rate so far */
  1148.   if (v->xpru.xpru_filesize < 0)
  1149.     expect = 1;                /* Don't know filesize; display time=1; was 0 thas to nice for GURU 8000 0005 */
  1150.   else
  1151.   {
  1152.    if((v->xpru.xpru_datarate != 0) && ((v->xpru.xpru_filesize - v->Strtpos) != 0))
  1153.       expect = (v->xpru.xpru_filesize - v->Strtpos) / v->xpru.xpru_datarate;
  1154.     else
  1155.       expect = 1; /* Display 1 secs better than nothing... */
  1156.   }
  1157.  
  1158.   hr = expect / 3600;                /* How many whole hours */
  1159.   expect -= hr * 3600;                /* Remainder not counting hours */
  1160.   min = expect / 60;                /* How many whole minutes */
  1161.   expect -= min * 60;                /* Remaining seconds */
  1162.   xprsprintf (v->Msgbuf, "%02ld:%02ld:%02ld", (long) hr, (long) min, expect);
  1163.   v->xpru.xpru_expecttime = (char *) v->Msgbuf;
  1164.  
  1165.   /* Compute elapsed time for this transfer so far */
  1166.   elapsed /= 128;
  1167.   hr = elapsed / 3600;
  1168.   elapsed -= hr * 3600;
  1169.   min = elapsed / 60;
  1170.   elapsed -= min * 60;
  1171.   xprsprintf (v->Msgbuf + 20, "%02ld:%02ld:%02ld", (long) hr, (long) min,
  1172.               elapsed);
  1173.   v->xpru.xpru_elapsedtime = (char *) v->Msgbuf + 20;
  1174. }                                /* End of void update_rate() */
  1175.  
  1176. /**********************************************************
  1177.  *      long bfopen(struct Vars *v, UBYTE *mode)
  1178.  *
  1179.  * Buffered file I/O fopen() interface routine
  1180.  **********************************************************/
  1181. long
  1182. bfopen (struct Vars *v, UBYTE * mode)
  1183. {
  1184.   /* Initialize file-handling variables */
  1185.   v->Filebufpos = v->Filebuflen = v->Filebufcnt = 0;
  1186.   v->Fileflush = FALSE;
  1187.   v->Filebufptr = v->Filebuf;
  1188.   /* Open the file */
  1189. #ifdef DEBUGLOG
  1190.   xprsprintf (v->Msgbuf, "bfopen: %s %s\n", v->Filename, mode);
  1191.   dlog (v, v->Msgbuf);
  1192.   D (DEBUGINFO);
  1193. #endif
  1194.   return (*v->io.xpr_fopen) (v->Filename, mode);
  1195. }                                /* End of long bfopen() */
  1196.  
  1197. /**********************************************************
  1198.  *      void bfclose(struct Vars *v)
  1199.  *
  1200.  * Buffered file I/O fclose() interface routine
  1201.  **********************************************************/
  1202. void
  1203. bfclose (struct Vars *v)
  1204. {
  1205. #ifdef DEBUGLOG
  1206.   D (DEBUGINFO);
  1207. #endif
  1208.  
  1209.   if (v->File)
  1210.     {
  1211.       /* If bfwrite() left data in buffer, flush it out before closing */
  1212.       if (v->Fileflush)
  1213.         (*v->io.xpr_fwrite) (v->Filebuf, 1L, v->Filebufcnt, v->File);
  1214.       /* Close the file */
  1215.       (*v->io.xpr_fclose) (v->File);
  1216.       v->File = NULL;
  1217.     }
  1218. }                                /* End of void bfclose() */
  1219.  
  1220. /**********************************************************
  1221.  *      void bfseek(struct Vars *v, long pos)
  1222.  *
  1223.  * Buffered file I/O fseek() interface routine
  1224.  **********************************************************/
  1225. void
  1226. bfseek (struct Vars *v, long pos)
  1227. {
  1228.   long offset;
  1229.  
  1230. #ifdef DEBUGLOG
  1231.   D (DEBUGINFO);
  1232. #endif
  1233.  
  1234.   /* If new file position is within currently buffered section,
  1235.      reset pointers */
  1236.   if (pos >= v->Filebufpos && pos < v->Filebufpos + v->Filebuflen)
  1237.     {
  1238.       offset = pos - v->Filebufpos;
  1239.       v->Filebufptr = v->Filebuf + offset;
  1240.       v->Filebufcnt = v->Filebuflen - offset;
  1241.       /* Otherwise, fseek() file & discard buffer contents to force new read */
  1242.     }
  1243.   else
  1244.     {
  1245.       (*v->io.xpr_fseek) (v->File, pos, 0L);
  1246.       v->Filebuflen = v->Filebufcnt = 0;
  1247.       v->Filebufpos = pos;
  1248.     }
  1249. }                                /* End of void bfseek() */
  1250.  
  1251. /**********************************************************
  1252.  *      long bfread(struct Vars *v, UBYTE *buf, long length)
  1253.  *
  1254.  * Buffered file I/O fread() interface routine
  1255.  **********************************************************/
  1256. long
  1257. bfread (struct Vars *v, UBYTE * buf, long length)
  1258. {
  1259.   long count, total = 0;
  1260.  
  1261. #ifdef DEBUGLOG
  1262.   D (DEBUGINFO);
  1263. #endif
  1264.  
  1265.   /* Keep going until entire request completed */
  1266.   while (length > 0)
  1267.     {
  1268.       /* Copy as much of the request as possible from the buffer */
  1269.       count = (length <= v->Filebufcnt) ? length : v->Filebufcnt;
  1270.       CopyMem (v->Filebufptr, buf, count);
  1271. #ifdef DEBUGLOG
  1272.       xprsprintf (v->Msgbuf, "bfread got %ld bytes from buffer\n", count);
  1273.       dlog (v, v->Msgbuf);
  1274.       D (DEBUGINFO);
  1275. #endif
  1276.       buf += count;
  1277.       total += count;
  1278.       length -= count;
  1279.       v->Filebufptr += count;
  1280.       v->Filebufcnt -= count;
  1281.  
  1282.       /* If we've emptied the buffer, read next buffer's worth */
  1283.       if (!v->Filebufcnt)
  1284.         {
  1285.           v->Filebufpos += v->Filebuflen;
  1286.           v->Filebufptr = v->Filebuf;
  1287.           v->Filebufcnt = v->Filebuflen
  1288.             = (*v->io.xpr_fread) (v->Filebuf, 1L, v->Filebufmax, v->File);
  1289. #ifdef DEBUGLOG
  1290.           xprsprintf (v->Msgbuf, "bfread read %ld bytes\n", v->Filebufcnt);
  1291.           dlog (v, v->Msgbuf);
  1292.           D (DEBUGINFO);
  1293. #endif
  1294.           /* If we hit the EOF, return with however much we read so far */
  1295.           if (!v->Filebufcnt)
  1296.             break;
  1297.         }
  1298.     }
  1299.   return total;
  1300. }                                /* End of long bfread() */
  1301.  
  1302. /**********************************************************
  1303.  *      long bfwrite(struct Vars *v, UBYTE *buf, long length)
  1304.  *
  1305.  * Buffered file I/O fwrite() interface routine
  1306.  **********************************************************/
  1307. long
  1308. bfwrite (struct Vars *v, UBYTE * buf, long length)
  1309. {
  1310.   long count, total = 0;
  1311.  
  1312. #ifdef DEBUGLOG
  1313.   D (DEBUGINFO);
  1314. #endif
  1315.  
  1316.   /* Keep going until entire request completed */
  1317.   while (length > 0)
  1318.     {
  1319.       /* Copy as much as will fit into the buffer */
  1320.       count = v->Filebufmax - v->Filebufcnt;
  1321.       if (length < count)
  1322.         count = length;
  1323.       CopyMem (buf, v->Filebufptr, count);
  1324. #ifdef DEBUGLOG
  1325.       xprsprintf (v->Msgbuf, "bfwrite buffered %ld bytes\n", count);
  1326.       dlog (v, v->Msgbuf);
  1327.       D (DEBUGINFO);
  1328. #endif
  1329.       buf += count;
  1330.       total += count;
  1331.       length -= count;
  1332.       v->Filebufptr += count;
  1333.       v->Filebufcnt += count;
  1334.       v->Fileflush = TRUE;
  1335.  
  1336.       /* If we've filled the buffer, write it out */
  1337.       if (v->Filebufcnt == v->Filebufmax)
  1338.       {
  1339.         count = (*v->io.xpr_fwrite) (v->Filebuf, 1L, v->Filebufcnt, v->File);
  1340. #ifdef DEBUGLOG
  1341. xprsprintf (v->Msgbuf, "bfwrite wrote %ld bytes\n", count);
  1342. dlog (v, v->Msgbuf);
  1343. D (DEBUGINFO);
  1344. #endif
  1345.         if (count < v->Filebufcnt)
  1346.           return -1;
  1347.         v->Filebufptr = v->Filebuf;
  1348.         v->Filebufcnt = 0;
  1349.         v->Fileflush = FALSE;
  1350.       }
  1351.     }
  1352.   return total;
  1353. }                                /* End of long bfwrite() */
  1354.  
  1355. /**********************************************************
  1356.  *      void ioerr(struct XPR_IO *io, char *msg)
  1357.  *
  1358.  * Have the comm program display an error message for us,
  1359.  * using a temporary XPR_UPDATE structure; used to display
  1360.  * errors before Vars gets allocated
  1361.  **********************************************************/
  1362. void
  1363. ioerr (struct XPR_IO *io, char *msg)
  1364. {
  1365.   struct XPR_UPDATE xpru;
  1366.  
  1367.   if (io->xpr_update)
  1368.     {
  1369.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  1370.       xpru.xpru_errormsg = msg;
  1371.       (*io->xpr_update) (&xpru);
  1372.     }
  1373. }                                /* End of void ioerr() */
  1374.  
  1375. /**********************************************************
  1376.  *     void updstatus(struct Vars *v,char *filename,long status)
  1377.  *
  1378.  * Set the pass/fail status of this file
  1379.  * Have the comm program display the file status for us, using the
  1380.  * normal XPR_IO structure allocated in Vars
  1381.  **********************************************************/
  1382. void
  1383. updstatus (struct Vars *v, char *filename, long status, long mask)
  1384. {
  1385.   if (v->NoMask) mask=0;
  1386.   v->xpru.xpru_updatemask = XPRU_FILENAME | XPRU_STATUS | mask;
  1387.   v->xpru.xpru_filename = filename;
  1388.   v->xpru.xpru_status = status;
  1389.   (*v->io.xpr_update) (&v->xpru);
  1390. }
  1391.  
  1392. /**********************************************************
  1393.  *      void upderr(struct Vars *v, char *msg)
  1394.  *
  1395.  * Have the comm program display an error message for us, using the
  1396.  * normal XPR_IO structure allocated in Vars
  1397.  **********************************************************/
  1398. void
  1399. upderr (struct Vars *v, char *msg, long mask)
  1400. {
  1401.   if (v->NoMask) mask=0;
  1402.   v->xpru.xpru_updatemask = XPRU_ERRORMSG | mask;
  1403.   v->xpru.xpru_errormsg = msg;
  1404.   if (msg == v->Msgbuf)                /* Ensure message length < 50 */
  1405.     msg[48] = '\0';
  1406.   (*v->io.xpr_update) (&v->xpru);
  1407. #ifdef DEBUGLOG
  1408.   dlog (v, msg);
  1409.   dlog (v, "\n");
  1410.   D (DEBUGINFO);
  1411. #endif
  1412. }                                /* End of void upderr() */
  1413.  
  1414. /**********************************************************
  1415.  *      void updmsg(struct Vars *v,char *msg)
  1416.  *
  1417.  * Have the comm program display a normal message for us
  1418.  **********************************************************/
  1419. void
  1420. updmsg (struct Vars *v, char *msg, long mask)
  1421. {
  1422. #ifdef DEBUGLOG
  1423.   D (DEBUGINFO);
  1424. #endif
  1425.  
  1426.   if (v->NoMask) mask=0;
  1427.   v->xpru.xpru_updatemask = XPRU_MSG | mask;
  1428.   v->xpru.xpru_msg = msg;
  1429.   if (msg == v->Msgbuf)                /* Ensure message length < 50 */
  1430.     msg[48] = '\0';
  1431.   (*v->io.xpr_update) (&v->xpru);
  1432. #ifdef DEBUGLOG
  1433.   dlog (v, msg);
  1434.   dlog (v, "\n");
  1435.   D (DEBUGINFO);
  1436. #endif
  1437. }                                /* End of void updmsg() */
  1438.  
  1439. /**********************************************************
  1440.  *      long getfree(void)
  1441.  *
  1442.   * Figure out how many bytes are free on the drive we're uploading to.
  1443.  * Stubbed out for now; not supported by XPR spec.
  1444.  **********************************************************/
  1445. long
  1446. getfree (void)
  1447. {
  1448.   return 0x7FFFFFFF;
  1449. }                                /* End of long getfree() */
  1450.  
  1451. /**********************************************************
  1452.  *      char exist(struct Vars *v)
  1453.  *
  1454.  * Check whether file already exists; used to detect
  1455.  * potential overwrites
  1456.  **********************************************************/
  1457. char
  1458. exist (struct Vars *v)
  1459. {
  1460.   long file;
  1461.  
  1462. #ifdef DEBUGLOG
  1463.   D (DEBUGINFO);
  1464. #endif
  1465.  
  1466.   file = (*v->io.xpr_fopen) (v->Filename, "r");
  1467.   if (file)
  1468.   {
  1469.       (*v->io.xpr_fclose) (file);
  1470.       return TRUE;
  1471.   }
  1472.   else
  1473.   {
  1474.     return FALSE;
  1475.   }
  1476. }                                /* End of char exist() */
  1477.  
  1478. #ifdef DEBUGLOG
  1479. /**********************************************************
  1480.  *      void dlog(struct Vars *v, UBYTE *s)
  1481.  *
  1482.  * Write a message to the debug log
  1483.  **********************************************************/
  1484. void
  1485. dlog (struct Vars *v, UBYTE * s)
  1486. {
  1487.   /* Open the debug log if it isn't already open */
  1488.   if (!DebugLog)
  1489.     DebugLog = (char *) (*v->io.xpr_fopen) (DebugName, "a");
  1490.   (*v->io.xpr_fwrite) (s, 1L, (long) strlen (s), (long) DebugLog);
  1491.   /*
  1492.      * Close file to flush output buffer; comment these two lines out if
  1493.      * you aren't crashing your system and don't mind waiting until the
  1494.      * transfer finishes to look at your log file.
  1495.    */
  1496.   /* (*v->io.xpr_fclose)((long)DebugLog);
  1497.      * DebugLog = NULL;
  1498.    */
  1499.  
  1500. }                                /* End of void dlog() */
  1501. #endif
  1502. /* End of Utils.c source */
  1503.